<?php

namespace app\index\dao;

use app\common\model\Consulting;
use app\common\model\ConsultingMessage;
use app\index\dao\traits\UidTrait;
use ShidianUtil\Concurrent\Synchronizer;
use ShidianUtil\Thinkphp\Dao\DaoTrait;
use ShidianUtil\Utils\TimeUtil;
use think\Collection;

/**
 * ConsultingDao 数据访问对象
 * Class ConsultingDao
 * @package app\dao
 * @method Consulting findByPK(?int $id, $field = true)
 * @method \think\Collection selectAll(?int $page, ?int $page_size, $field = true)
 * @method Consulting insertActive(array $params, array $allow_field = [])
 * @method Consulting updateActive(Consulting $model, array $params, array $allow_field = [])
 * @method Consulting findAndUpdateActive(int $id, array $params, array $allow_field = [])
 * @method Consulting updateActiveByClosure(\Closure $closure, array $params, array $allow_field = [])
 * @method void deleteModel(Consulting $model)
 * @method void deleteById(int|array|\Closure $id, bool $force = false)
 * @link https://www.kancloud.cn/manual/thinkphp6_0/1037579
 * @link https://www.kancloud.cn/manual/think-orm/1257998
 * @link https://www.kancloud.cn/thinkphp/master-database-and-model/265551
 */
class ConsultingDao
{
    use DaoTrait;
    use UidTrait;

    /**
     * @var \app\common\model\Consulting
     */
    private $baseModel;

    /**
     * ConsultingDao constructor.
     */
    public function __construct()
    {
        $this->baseModel = Consulting::class;
    }

    /**
     * 插入咨询（如果已存在，那么返回已存在的咨询）
     * @param $params
     * @return Consulting|null
     */
    public function findORInsertConsulting($params): ?Consulting
    {

        // 如果指定了律师
        if (is_id($params['lawyerId'])) {

            // 读取和该律师的咨询
            $record = Consulting::where('memberId', $params['memberId'])
                ->where('lawyerId', $params['lawyerId'])
                ->where('isEnd', 0)
                ->find();

            if ($record) {

                $record->memberHiddenTime = 0;
                $record->save();

                $record->isNew = 0;
                return $record;
            }
        }

        $record = $this->insertConsulting($params);

        $record->isNew = 1;

        return $record;
    }

    /**
     * 插入咨询
     * @param $params
     * @return Consulting|null
     */
    public function insertConsulting($params)
    {
        $record = null;

        $signature = __CLASS__;
        $this->getSynchronizer()->synchronized($signature, function () use ($params, &$record) {

            if (is_blank($params['no'] ?? null)) {
                $params['no'] = $this->getUid(3);
            }

            $record = $this->insertActive($params);
        });

        if (!$record) {
            throw new \RuntimeException('创建失败，请稍后再试');
        }

        return $record;
    }

    /**
     * 统计一天创建了多少免费的咨询
     * @param $memberId
     * @param int|null $day_time
     * @return int
     * @throws \think\db\exception\DbException
     */
    public function countConsultingByDay($memberId, ?int $day_time = null): int
    {

        if (is_null($day_time)) {
            $day_time = TimeUtil::stamp(TimeUtil::DAY);
        }

        return Consulting::where('memberId', $memberId)
            ->where('consultingType', 0)
            ->where('created', '>=', $day_time)
            ->where('created', '<', $day_time + 86400)
            ->count();
    }

    /**
     * H5推广页用的咨询详情
     * @param $id
     * @return Consulting|null
     */
    public function findOfAd($id): ?Consulting
    {

        return Consulting::where('id', $id)
            ->field(['id', 'memberId', 'robotId', 'ask', 'pf', 'chain', 'promotionGroupId'])
            ->with([
                'member' => fn($query) => $query->memberBasicInfo(),
                'robot' => fn($query) => $query->robotBasicInfo(),
            ])
            ->find();
    }

    /**
     * 聊天用的详情
     * @param $id
     * @return \app\common\model\Consulting|null
     */
    public function findOfChat($id): ?Consulting
    {
        return Consulting::where('id', $id)
            ->with([
                'member' => fn($query) => $query->field(['id', 'phone']),
                'lawCase' => fn($query) => $query->field(['id', 'questionId'])
            ])
            ->find();
    }

    /**
     * 用户聊天室列表
     * @param $memberId
     * @param $page
     * @param $page_size
     * @return Collection|null
     */
    public function selectChatsOfMember($memberId, $page, $page_size): ?Collection
    {
        $lastTimeField = 'memberLastTime';
        $hiddenTimeField = 'memberHiddenTime';

        // 用户
        $query = Consulting::where('memberId', $memberId)
            ->whereRaw('lastChatTime >= memberHiddenTime');

        return $this->queryChatsWhere($query, $lastTimeField, $hiddenTimeField)
            ->order('lastChatTime', 'DESC')
            ->order('id', 'DESC')
            ->paging($page, $page_size)
            ->select()
            ->each(function (Consulting $consulting) {
                if ($consulting->lawyer) {
                    $consulting->setRelation('chatMember', $consulting->lawyer);
                } else {
                    $consulting->setRelation('chatMember', $consulting->robot);
                }
            });
    }

    /**
     * 律师聊天室列表
     * @param $memberId
     * @param $page
     * @param $page_size
     * @return Collection|null
     */
    public function selectChatsOfLawyer($memberId, $page, $page_size): ?Collection
    {

        $lastTimeField = 'lawyerLastTime';
        $hiddenTimeField = 'lawyerHiddenTime';

        // 律师
        $query = Consulting::where('lawyerId', $memberId)
            ->whereRaw('lastChatTime >= lawyerHiddenTime')
            ->where('rushStatus', 2);

        return $this->queryChatsWhere($query, $lastTimeField, $hiddenTimeField)
            ->order('lastChatTime', 'DESC')
            ->order('id', 'DESC')
            ->paging($page, $page_size)
            ->select()
            ->each(function (Consulting $consulting) {
                $consulting->setRelation('chatMember', $consulting->member);
            });
    }

    private function queryChatsWhere($query, $lastTimeField, $hiddenTimeField)
    {
        $tableName = Consulting::getTable();
        $messageTableName = ConsultingMessage::getTable();

        // 最新一条消息的子查询
        $subSql = ConsultingMessage::field(['max(id)' => 'id'])->whereIn('senderType', ['member', 'robot'])->where('isDel', '0')->group('consultingId')->buildSql();

        // 待抢单的不算
        return $query->where(function ($query) {
            $query->whereOr('matchType', '<>', '2')
                ->whereOr('rushStatus', '<>', '0')
                ->whereOr('rushTimes', '>', 0);
        })->with([
            'consultingServer' => fn($query) => $query->field(['id', 'name']),

            'lawyer' => fn($query) => $query->field(['id', 'nickname', 'realname', 'headImgUrl', 'cropImgUrl', 'type'])
                ->append(['headImg', 'headImgThumb', 'cropImg', 'showName'])
                ->hidden(['headImgUrl']),

            'member' => fn($query) => $query->field(['id', 'nickname', 'realname', 'headImgUrl', 'cropImgUrl', 'type'])
                ->append(['headImg', 'headImgThumb', 'cropImg', 'showName'])
                ->hidden(['headImgUrl']),

            'robot' => fn($query) => $query->field(['id', 'nickname', 'headImgUrl', 'type'])
                ->append(['headImg', 'headImgThumb', 'cropImg', 'showName'])
                ->hidden(['headImgUrl']),

            'lastMessage' => fn($query) => $query->leftJoin([$subSql => 'cm'], "$messageTableName.id = cm.id")->whereRaw("$messageTableName.id = cm.id"),
        ])->withCount([
            'unreadMessages' => fn($query) => $query->whereRaw("count_table.messageTime >= $tableName.$lastTimeField")
                ->whereRaw("count_table.messageTime >= $tableName.$hiddenTimeField")
                ->whereIn('senderType', ['member', 'robot'])
        ])
            ->tableField(true, $tableName);
    }

    /**
     * 消息红点数
     * @param $memberId
     * @param $type
     * @return int
     */
    public function countMessageNumber($memberId, $type)
    {

        // 消息
        if ($type == 0) {
            $key = 'memberId';
            $key1 = 'memberLastTime';
            $key2 = 'memberHiddenTime';
        } elseif ($type == 1) {
            $key = 'lawyerId';
            $key1 = 'lawyerLastTime';
            $key2 = 'lawyerHiddenTime';
        }

        $tableName = ConsultingMessage::getTable();

        $query = ConsultingMessage::leftJoin('consulting c', "$tableName.consultingId=c.id and c.$key = :id", ['id' => $memberId])
            ->where("c.$key", $memberId)
            ->whereRaw("$tableName.messageTime>=c.$key1")
            ->whereRaw("$tableName.messageTime>=c.$key2")
            ->whereIn('senderType', ['member', 'robot']);

        if ($type == 1) {
            $query->where('rushStatus', 2);
        }

        return $query->where(function ($query) {
            $query->whereOr('c.matchType', '<>', '2')
                ->whereOr('c.rushStatus', '<>', '0')
                ->whereOr('c.rushTimes', '>', 0);
        })->where('isDel', '0')
            ->count();
    }

    /**
     * 律师端-抢单列表
     * @param $lawyerId
     * @param $cityId
     * @param $page
     * @param $page_size
     * @return Collection
     */
    public function selectCanRush($lawyerId, $categoryId, $cityId, $page, $page_size): Collection
    {
        $tableName = Consulting::getTable();
        // 可抢单的列表
        return Consulting::leftJoin('consulting_ignore ci', "$tableName.id=ci.consultingId and ci.lawyerId=:lawyerId", ['lawyerId' => $lawyerId])
            ->when(is_id($categoryId), fn($query) => $query->where('categoryId', $categoryId))
            ->when(is_id($cityId), fn($query) => $query->where('cityId', $cityId))
            ->where("$tableName.matchType", 2)
            ->where("$tableName.lawyerId", 0)
            ->where("$tableName.status", 1)
            ->whereNull('ci.consultingId')
            ->with([
                'consultingSubsidy',
                'consultingServer' => fn($query) => $query->field(['id', 'name', 'icon'])->append(['iconImg']),
                'province' => fn($query) => $query->shortArea(),
                'city' => fn($query) => $query->shortArea(),
            ])
            ->order("$tableName.id", 'DESC')
            ->paging($page, $page_size)
            ->select();
    }

    /**
     * 律师端-抢单列表V2
     * @param array|null $consultingServerIds
     * @param $page
     * @param $page_size
     * @return Collection
     */
    public function selectCanRushV2(?array $consultingServerIds, $page, $page_size): Collection
    {
        if (!is_null($consultingServerIds) && empty($consultingServerIds)) {
            return \think\model\Collection::make();
        }

        $tableName = Consulting::getTable();

        // 可抢单的列表
        return Consulting::when(!is_null($consultingServerIds), fn($query) => $query->whereIn('consultingServerId', $consultingServerIds))
            ->where("$tableName.matchType", 2)
            ->where("$tableName.lawyerId", 0)
            ->where("$tableName.status", 1)
            ->where("$tableName.isEnd", 0)
            ->with([
                'category',
                'consultingServer' => fn($query) => $query->field(['id', 'name', 'icon'])->append(['iconImg']),
                'province' => fn($query) => $query->shortArea(),
                'city' => fn($query) => $query->shortArea(),
            ])
            ->order("$tableName.id", 'DESC')
            ->paging($page, $page_size)
            ->select();
    }

    /**
     * 律师端-抢单列表V3
     * 展示历史数据
     * @param array|null $consultingServerIds
     * @param $page
     * @param $page_size
     * @return Collection
     */
    public function selectRushV3(array $rushStatus, ?array $consultingServerIds, $page, $page_size): Collection
    {
        if (!is_null($consultingServerIds) && empty($consultingServerIds)) {
            return \think\model\Collection::make();
        }

        $tableName = Consulting::getTable();

        return Consulting::when(!is_null($consultingServerIds), fn($query) => $query->whereIn('consultingServerId', $consultingServerIds))
            ->where("$tableName.matchType", Consulting::MATCH_TYPE_RUSH)
            ->where("$tableName.status", 1)
            ->whereIn('rushStatus', $rushStatus)
            ->with([
                'category',
                'consultingServer' => fn($query) => $query->field(['id', 'name', 'icon'])->append(['iconImg']),
                'province' => fn($query) => $query->shortArea(),
                'city' => fn($query) => $query->shortArea(),
            ])
            ->withAttr([
                'created' => fn($value) => date('Y-m-d H:i:s', $value)
            ])
            ->order('rushStatus', 'ASC')
            ->order("$tableName.id", 'DESC')
            ->paging($page, $page_size)
            ->select();
    }

    /**
     * 律师端-工作台-待处理咨询
     * @param $lawyerId
     * @param $page
     * @param $page_size
     * @return Collection
     */
    public function selectWorkbench($lawyerId, $consultingServerId, $page, $page_size): Collection
    {
        return Consulting::where('lawyerId', $lawyerId)
            ->when(is_id($consultingServerId), fn($query) => $query->where('consultingServerId', $consultingServerId))
            ->where('status', 1)
            ->where('rushStatus', 1)
            ->where(function ($query) {
                $query->whereOr('isAsked', 1)
                    ->whereOr('consultingType', 1);
            })
            ->with([
                'consultingSubsidy',
                'consultingServer' => fn($query) => $query->field(['id', 'name', 'icon'])->append(['iconImg']),
                'province' => fn($query) => $query->shortArea(),
                'city' => fn($query) => $query->shortArea(),
            ])
            ->order('lastChatTime', 'DESC')
            ->order('id', 'DESC')
            ->paging($page, $page_size)
            ->select();
    }

    /**
     * 律师端-统计工作台咨询数量
     * @param $lawyerId
     * @return int
     */
    public function countWorkbench($lawyerId)
    {
        return Consulting::where('lawyerId', $lawyerId)
            ->where('status', 1)
            ->where('rushStatus', 1)
            ->where(function ($query) {
                $query->whereOr('isAsked', 1)
                    ->whereOr('consultingType', 1);
            })
            ->count();
    }

    private function getSynchronizer(): Synchronizer
    {
        return app(Synchronizer::class);
    }
}
